/*
 * @Author: 来自火星的码农 15122322+heyzhi@user.noreply.gitee.com
 * @Date: 2025-10-01 17:30:44
 * @LastEditors: 来自火星的码农 15122322+heyzhi@user.noreply.gitee.com
 * @LastEditTime: 2025-10-01 18:48:58
 * @FilePath: /GateServer/src/util/logger.h
 * @Description: Logger header file with console and file output
 */
#pragma once

#include "spdlog/spdlog.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include <stdexcept>
#include <string>
#include <memory>
#include <vector>
#include <cstdarg>

// 跨平台兼容定义
#ifdef _WIN32
    #define VSPRINTF vsprintf_s
    #define VSCPRINTF _vscprintf
    #include <direct.h>
    #define CREATE_DIR(path) _mkdir(path)
    #define DIR_EXISTS(path) (_access(path, 0) == 0)
#else
    #define VSPRINTF vsnprintf
    #include <sys/stat.h>
    #include <unistd.h>
    #define CREATE_DIR(path) mkdir(path, 0755)
    #define DIR_EXISTS(path) (access(path, F_OK) == 0)
    
    inline int calculate_va_length(const char* format, va_list args) {
        va_list args_copy;
        va_copy(args_copy, args);
        int length = vsnprintf(nullptr, 0, format, args_copy);
        va_end(args_copy);
        return length;
    }
    #define VSCPRINTF calculate_va_length
#endif

class Log
{
public:
    enum OutputTarget {
        FILE_ONLY = 0,    // 仅文件
        CONSOLE_ONLY = 1, // 仅控制台
        BOTH = 2          // 文件和控制台
    };

    static Log& GetInstance(const std::string& log_path = "./logs/", 
                           OutputTarget target = BOTH,
                           spdlog::level::level_enum level = spdlog::level::trace)
    {
        static Log instance(log_path, target, level);
        return instance;
    }

    inline std::shared_ptr<spdlog::logger> GetLogger() { return logger; }

    // 便捷的日志方法
    template<typename... Args>
    inline void trace(const char* fmt, const Args&... args) {
        logger->trace(fmt, args...);
    }
    
    template<typename... Args>
    inline void debug(const char* fmt, const Args&... args) {
        logger->debug(fmt, args...);
    }
    
    template<typename... Args>
    inline void info(const char* fmt, const Args&... args) {
        logger->info(fmt, args...);
    }
    
    template<typename... Args>
    inline void warn(const char* fmt, const Args&... args) {
        logger->warn(fmt, args...);
    }
    
    template<typename... Args>
    inline void error(const char* fmt, const Args&... args) {
        logger->error(fmt, args...);
    }
    
    template<typename... Args>
    inline void critical(const char* fmt, const Args&... args) {
        logger->critical(fmt, args...);
    }

private:
    Log(const std::string& log_path = "./logs/", 
        OutputTarget target = BOTH,
        spdlog::level::level_enum level = spdlog::level::trace)
    {
        // 确保日志目录存在（如果需要文件输出）
        if ((target == FILE_ONLY || target == BOTH) && !DIR_EXISTS(log_path.c_str()))
        {
            if (CREATE_DIR(log_path.c_str()) != 0) {
                throw std::runtime_error("Failed to create log directory: " + log_path);
            }
        }

        try {
            std::vector<spdlog::sink_ptr> sinks;

            // 添加控制台sink
            if (target == CONSOLE_ONLY || target == BOTH) {
                auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
                console_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v");
                sinks.push_back(console_sink);
            }

            // 添加文件sink
            if (target == FILE_ONLY || target == BOTH) {
                auto file_sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>(
                    log_path + "application.log", 0, 0);
                file_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] ThreadId:%5t Loglevel:%8l | %v");
                sinks.push_back(file_sink);
            }

            if (sinks.empty()) {
                throw std::runtime_error("No output target specified");
            }

            // 创建logger
            logger = std::make_shared<spdlog::logger>("multi_sink", sinks.begin(), sinks.end());
            logger->set_level(level);
            logger->flush_on(spdlog::level::trace);
            
            spdlog::set_default_logger(logger);
            
        } catch (const spdlog::spdlog_ex& ex) {
            throw std::runtime_error(std::string("Log initialization failed: ") + ex.what());
        }
    }

    ~Log()
    {
        spdlog::shutdown();
    }

    Log(const Log&) = delete;
    Log& operator=(const Log&) = delete;

private:
    std::shared_ptr<spdlog::logger> logger;
};

// 使用宏简化调用 - 完整的日志级别
#define LOG_TRACE(...)    Log::GetInstance().GetLogger()->trace(__VA_ARGS__)
#define LOG_DEBUG(...)    Log::GetInstance().GetLogger()->debug(__VA_ARGS__)
#define LOG_INFO(...)     Log::GetInstance().GetLogger()->info(__VA_ARGS__)
#define LOG_WARN(...)     Log::GetInstance().GetLogger()->warn(__VA_ARGS__)
#define LOG_ERROR(...)    Log::GetInstance().GetLogger()->error(__VA_ARGS__)
#define LOG_CRITICAL(...) Log::GetInstance().GetLogger()->critical(__VA_ARGS__)

// C风格API声明
extern void LogTrace(const char* format, ...);
extern void LogDebug(const char* format, ...);
extern void LogInfo(const char* format, ...);
extern void LogWarn(const char* format, ...);
extern void LogError(const char* format, ...);
extern void LogCritical(const char* format, ...);

extern void SetLogTrace();
extern void SetLogDebug();
extern void SetLogInfo();
extern void SetLogWarn();
extern void SetLogError();
extern void SetLogCritical();
extern void SetLogOff();

// ========== 实现部分 ==========
namespace detail {
    template <spdlog::level::level_enum Level>
    void LogV(const char* format, va_list args) {
        auto logger = Log::GetInstance().GetLogger();
        if (!logger || logger->level() > Level)
            return;

        int length = VSCPRINTF(format, args);
        if (length <= 0) return;

        std::vector<char> buffer(static_cast<size_t>(length) + 1);
        if (VSPRINTF(buffer.data(), buffer.size(), format, args) > 0) {
            if constexpr (Level == spdlog::level::trace)
                logger->trace(buffer.data());
            else if constexpr (Level == spdlog::level::debug)
                logger->debug(buffer.data());
            else if constexpr (Level == spdlog::level::info)
                logger->info(buffer.data());
            else if constexpr (Level == spdlog::level::warn)
                logger->warn(buffer.data());
            else if constexpr (Level == spdlog::level::err)
                logger->error(buffer.data());
            else if constexpr (Level == spdlog::level::critical)
                logger->critical(buffer.data());
        }
    }
}

// 日志函数实现
#define IMPLEMENT_LOG_FUNCTION(level_name, level_enum) \
inline void Log##level_name(const char* format, ...) { \
    va_list args; \
    va_start(args, format); \
    detail::LogV<spdlog::level::level_enum>(format, args); \
    va_end(args); \
}

IMPLEMENT_LOG_FUNCTION(Trace, trace)
IMPLEMENT_LOG_FUNCTION(Debug, debug)
IMPLEMENT_LOG_FUNCTION(Info, info)
IMPLEMENT_LOG_FUNCTION(Warn, warn)
IMPLEMENT_LOG_FUNCTION(Error, err)
IMPLEMENT_LOG_FUNCTION(Critical, critical)

// 设置日志级别函数
#define IMPLEMENT_SET_LEVEL_FUNCTION(level_name, level_enum) \
inline void SetLog##level_name() { \
    auto logger = Log::GetInstance().GetLogger(); \
    if (logger) logger->set_level(spdlog::level::level_enum); \
}

IMPLEMENT_SET_LEVEL_FUNCTION(Trace, trace)
IMPLEMENT_SET_LEVEL_FUNCTION(Debug, debug)
IMPLEMENT_SET_LEVEL_FUNCTION(Info, info)
IMPLEMENT_SET_LEVEL_FUNCTION(Warn, warn)
IMPLEMENT_SET_LEVEL_FUNCTION(Error, err)
IMPLEMENT_SET_LEVEL_FUNCTION(Critical, critical)

inline void SetLogOff() {
    auto logger = Log::GetInstance().GetLogger();
    if (logger) logger->set_level(spdlog::level::off);
}